package com.siqi.hr.system.common.sql;

import com.siqi.hr.system.common.chan.BeSql;
import com.siqi.hr.system.common.model.ModuleType;
import com.siqi.hr.system.common.utils.SqlBuildUtil;
import com.siqi.hr.system.common.utils.intf.BaseEnum;
import org.apache.commons.lang.StringUtils;

import java.util.HashSet;
import java.util.Set;

public class Condition implements BeSql {
    /**
     * 字段信息
     */
    private SField field;
    /**
     * 拼接sql的方法(如：等于、不等于、为空、不为空等)
     */
    private ConditionType type;
    /**
     * 字段值
     */
    private String value;

    public SField getField() {
        return this.field;
    }

    public void setField(SField field) {
        this.field = field;
    }

    public ConditionType getType() {
        return this.type;
    }

    public void setType(ConditionType type) {
        this.type = type;
    }

    public String getValue() {
        return this.value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public StringBuilder toSqlString() {
        if ((this.type == ConditionType.notinclude) || (this.type == ConditionType.noteq)) {
            StringBuilder condSb = new StringBuilder();
            condSb.append(" ( " + this.field.toSqlString()).append(" " + this.type.getSqlkey() + " ").append(packValue()).append(" or ")
                    .append(this.field.toSqlString()).append(" is null ");
            if (this.field.getSFieldType().getName().toUpperCase().equals(SFieldType.DatabaseType.DECIMAL)) {
                condSb.append(" or ").append(this.field.toSqlString()).append(" = '' ");
            }
            condSb.append(" ) ");
            return condSb;
        }

        if (this.type == ConditionType.notnull) {
            return new StringBuilder().append(" ( " + this.field.toSqlString()
                    + " is not null and " + this.field.toSqlString()+ " <> '' ) ");
        }

        if (this.type == ConditionType.isnull) {
            return new StringBuilder().append(" ( " + this.field.toSqlString()
                    + " is null or " + this.field.toSqlString() + " = '' ) ");
        }

        if (this.type == ConditionType.eqor) {
            return new StringBuilder().append(" 2<1 or ").append(this.field.toSqlString()).append(" ")
                    .append(this.type.getSqlkey()).append(" ").append(packValue()).append(" or 2<1 ");
        }

        if ((this.type == ConditionType.in)
                && (StringUtils.contains(this.value, "null"))) {
            StringBuilder sb = new StringBuilder();
            if ((StringUtils.isBlank(packValue())) || (StringUtils.isBlank(packValue().trim())) || (StringUtils.equals(packValue(), "()"))){
                sb.append(this.field.toSqlString()).append(" is null ");
            }else {
                sb.append("(").append(this.field.toSqlString()).append(" " + this.type.getSqlkey() + " " + packValue())
                        .append(" or ").append(this.field.toSqlString()).append(" is null )");
            }
            return sb;
        }

        return new StringBuilder().append(this.field.toSqlString()).append(
                " " + this.type.getSqlkey() + " " + packValue());
    }

    public String packValue() {
        String pv = this.type.getValueDecoration() == null ? this.value : this.type.getValueDecoration().decoration(this.value,
                this.field.getSFieldType().getDatabaseType());
        return SqlBuildUtil.surroundValue(this.field.getSFieldType(), pv,this.type);
    }

    public static String packValue(SField field, Condition cond) {
        ConditionType type = cond.getType();
        String pv = type.getValueDecoration() == null ? cond.getValue() : type
                .getValueDecoration().decoration(cond.getValue(),
                        field.getSFieldType().getDatabaseType());

        return SqlBuildUtil.surroundValue(field.getSFieldType(), pv, type);
    }

    public Condition(SField field, ConditionType type, String value) {
        this.field = field;
        this.type = type;
        this.value = value;
    }

    public static enum ConditionType implements IConditionType {
        eq("=", null), noteq("<>", null), gt(">", null), lt("<", null), ge(
                ">=", null), le("<=", null), include("like",
                new ValueDecoration() {
                    public String decoration(String value,
                                             SFieldType.DatabaseType databaseType) {
                        return "%" + value + "%";
                    }
                }),

        notinclude("not like", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return "%" + value + "%";
            }
        }),

        beginwith("like", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return value + "%";
            }
        }),

        endwith("like", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return "%" + value;
            }
        }),

        in("in", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                value = StringUtils.replace(value, "&", ",");

                Set<String> set = new HashSet<String>();
                for (String v : value.split(",")) {
                    if (!v.trim().equals("null")) {
                        if ((!StringUtils.contains(v, "'"))
                                && ((databaseType.toString()
                                .equalsIgnoreCase(SFieldType.DatabaseType.VARCHAR
                                        .toString()))
                                || (databaseType.toString()
                                .equalsIgnoreCase(SFieldType.DatabaseType.DATE
                                        .toString())) || (databaseType
                                .toString()
                                .equalsIgnoreCase(SFieldType.DatabaseType.DATETIME
                                        .toString())))) {
                            set.add("'" + v + "'");
                        } else
                            set.add(v);
                    }

                }

                return "(" + StringUtils.join(set, ",") + ")";
            }
        }),

        notin("not in", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return "(" + value + ")";
            }
        }),

        between("between", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                if (databaseType == SFieldType.DatabaseType.INT) {
                    return value.split("_")[0] + " and " + value.split("_")[1];
                }
                return value.split("_")[0] + "' and '" + value.split("_")[1];
            }
        }),

        isnull("is", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return "null";
            }
        }),

        notnull("is", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return "not null";
            }
        }),

        exactlike("like", null), exactnotlike("not like", null), modulenull(
                "=", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return ModuleType.NO_MODULE;
            }
        }),

        modulenotnull("<>", new ValueDecoration() {
            public String decoration(String value,
                                     SFieldType.DatabaseType databaseType) {
                return ModuleType.NO_MODULE;
            }
        }),

        eqor("=", null),

        ral_w("ral_w", null),

        ral_x("ral_x", null),

        ral_f("ral_f", null),

        ral_x_w("ral_x_w", null),

        ral_x_f("ral_x_f", null),

        ral_w_f("ral_w_f", null),

        ral_no_x("ral_no_x", null),

        ral_no_f("ral_no_f", null);

        private String sqlkey;
        private ValueDecoration valueDecoration;

        private ConditionType(String sqlkey,
                              ValueDecoration valueDecoration) {
            this.sqlkey = sqlkey;
            this.valueDecoration = valueDecoration;
        }

        public String getCode() {
            return null;
        }

        public String getDesc() {
            return null;
        }

        public String getSqlkey() {
            return this.sqlkey;
        }

        public ValueDecoration getValueDecoration() {
            return this.valueDecoration;
        }
    }

    private static abstract interface IConditionType extends BaseEnum<String> {
        public abstract String getSqlkey();

        public abstract ValueDecoration getValueDecoration();
    }

    public static abstract interface ValueDecoration {
        public abstract String decoration(String paramString,
                                          SFieldType.DatabaseType paramDatabaseType);
    }
}
